#!/usr/bin/python
# coding:utf8
import argparse
import sys
import const
import re
import math

const.MARGIN_MULTIPLIER = 10000
const.MARGIN_CS_MULTIPLIER = 100
const.LONGSHORT_SCALE = 1000000
const.PNL_SCALE = 1000000

#display standard yearly statistics from pnl file
(p, t, f, sdate, edate, booksize) = (None, "yearly", "short",-1,-1,-1.0)

parser = argparse.ArgumentParser(description='Example with long option names',formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('-p', action="store", dest="p",type=str,default=None)
parser.add_argument('-t', action="store", dest="t",type=str,default=t)
parser.add_argument('-f', action="store", dest="f",type=str,default=f)

parser.add_argument('-s', action="store", dest="sdate",type=int,default=sdate)
parser.add_argument('-e', action="store", dest="edate",type=int,default=edate)
parser.add_argument('-b', action="store", dest="booksize",type=float,default=booksize)

if('p' in dir()):
    if len(sys.argv) < 2:
        print("Usage: simsummary.py pnl_file\n")
        sys.exit(-1)
    elif len(sys.argv) == 2:
        p = sys.argv[1]
    else:
        results = parser.parse_args()
        p = results.__dict__["p"]
        t = results.__dict__["t"]
        sdate = results.__dict__["sdate"]
        edate = results.__dict__["edate"]
        booksize = results.__dict__["booksize"]
        
DD_start = 0
DD_setst = 0 
DD_sum = 0 

XX_last = 0
ldate = 0

with open(p, 'r') as file:#打开文件
    off = -50      #设置偏移量
    while True:
        file.seek(off, 2) #seek(off, 2)表示文件指针：从文件末尾(2)开始向前50个字符(-50)
        lines = file.readlines() #读取文件指针范围内所有行
        if len(lines) >= 2: #判断是否最后至少有两行，这样保证了最后一行是完整的
            last_line = lines[-1] #取最后一行
            break
        #如果off为50时得到的readlines只有一行内容，那么不能保证最后一行是完整的
        #所以off翻倍重新运行，直到readlines不止一行
        off *= 2

lastline = last_line.split('\t')
srecent = int(lastline[0]) - 20000
stats = dict()

def doStats(XX, date, pnl, long, short, ret, sh_hld, sh_trd, b_share, t_share):
    if not stats.has_key(XX):
        stats.setdefault(XX, dict())
    if stats[XX].has_key('dates'):
        stats[XX]['dates'].append(int(date))
    else:
        stats[XX].setdefault('dates',[int(date)])
    curr_ret = pnl / booksize * 2 if booksize > 0 else ret
    if stats[XX].has_key('pnl'):
        stats[XX]['pnl']+=float(pnl)
    else:
        stats[XX].setdefault('pnl', 0)
    if stats[XX].has_key('long'):
        stats[XX]['long']+=float(long)
    else:
        stats[XX].setdefault('long', 0)
    if stats[XX].has_key('short'):
        stats[XX]['short']+=float(short)
    else:
        stats[XX].setdefault('short', 0)
    if stats[XX].has_key('sh_hld'):
        stats[XX]['sh_hld']+=float(sh_hld)
    else:
        stats[XX].setdefault('sh_hld', 0)
    if stats[XX].has_key('sh_trd'):
        stats[XX]['sh_trd']+=float(sh_trd)
    else:
        stats[XX].setdefault('sh_trd', 0)
    if stats[XX].has_key('avg_ret'):
        stats[XX]['avg_ret']+=float(curr_ret)
    else:
        stats[XX].setdefault('avg_ret', 0)
    if stats[XX].has_key('b_sh'):
        stats[XX]['b_sh']+=float(b_share)
    else:
        stats[XX].setdefault('b_sh', 0)
    if stats[XX].has_key('t_sh'):
        stats[XX]['t_sh']+=float(t_share)
    else:
        stats[XX].setdefault('t_sh', 0)
    
    if long != 0 or short != 0 or booksize > 0:
        if stats[XX].has_key('days'):
            stats[XX]['days']+=1
        else:
            stats[XX].setdefault('days',0)
        print(stats[XX]['days'])
        
    if stats[XX].has_key('xsy'):
        stats[XX]['xsy']+=float(curr_ret)
    else:
        stats[XX].setdefault('xsy', 0.0)
    if stats[XX].has_key('xsyy'):
        stats[XX]['xsyy']+=float(curr_ret) ** 2
    else:
        stats[XX].setdefault('xsyy', 0.0)
    
    if pnl > 0:
        if stats[XX].has_key('up_days'):
            stats[XX]['up_days']+=1
        else:
            stats[XX].setdefault('up_days', 0)

    if not stats.has_key('mm_sum'):
        stats[XX].setdefault('mm_sum', 0)
        stats[XX].setdefault('mm_cnt', 0)
        stats[XX].setdefault('up_months', 0)

    if not stats.has_key('ww_sum'):
        stats[XX].setdefault('ww_sum', 0)
        stats[XX].setdefault('ww_cnt', 0)
        stats[XX].setdefault('up_weeks', 0)

    if not stats.has_key('drawdown'):
        stats[XX].setdefault('drawdown', 0)
        stats[XX].setdefault('dd_start', 0)
        stats[XX].setdefault('dd_end', 0)

finalTimeHash = dict()
goodLong = dict()
goodShort = dict()
    
def canUpdate(date,long,short):
    if not goodLong.has_key('date') or not goodShort.has_key('date'):
        return 1
    else:
        curr_diff = abs(abs(long) + abs(short) - booksize)
        target_diff = abs(abs(goodLong['date']) + abs(goodShort['date']) - booksize)
        if(curr_diff <= target_diff):
            return 1
    return 0

with open(p) as F:
    for line in F:
        date, pnl, long, short,_,_,_,_,_,_ = line[:-1].split('\t')
        if len(date) < 9:
            break
        date_ = date[0:8]
        finalTimeHash[date_] = date #overwrite
        if booksize > 0 and canUpdate(date_,long,short) > 0:
            goodLong[date_] = long
            goodShort[date_] = short
            
with open(p) as F:
    for l in F:
        date, pnl, long, short, ret, sh_hld, sh_trd, b_share, t_share,_ = l[:-1].split('\t')
        date_ = date[0:8]
        if (sdate > 0 and date_ < sdate) or (edate > 0 and date_ > edate):
            continue
        if finalTimeHash.has_key(date_) and date != finalTimeHash[date_]:
            continue
        date = date[0:8]

        XX = date[0:4]
        if t == "monthly":
            XX = date[0:6]

        long = float(goodLong[date_]) if booksize > 0 else float(long)
        short = float(goodShort[date_]) if booksize > 0 else float(short)
        doStats(XX,date,pnl,long,short, ret, sh_hld, sh_trd, b_share, t_share)
        doStats("ALL",date,pnl,long,short, ret, sh_hld, sh_trd, b_share, t_share)

        if date > srecent:
            doStats("RECENT",date,pnl,long,short, ret, sh_hld, sh_trd, b_share, t_share)

        #drawdowns
        if DD_setst:
            DD_start = date
            DD_setst = 0

        DD_sum += float(pnl)
        if DD_sum >= 0:
            DD_sum = 0
            DD_start = date
            DD_setst = 1

        if DD_sum < stats[XX]['drawdown']:
            stats[XX]['drawdown'] = DD_sum
            stats[XX]['dd_start'] = DD_start
            stats[XX]['dd_end'] = date

        if DD_sum < stats['ALL']['drawdown']:
            stats['ALL']['drawdown'] = DD_sum
            stats['ALL']['dd_start'] = DD_start
            stats['ALL']['dd_end'] = date

        if date > srecent and DD_sum < stats['RECENT']['drawdown']:
            stats['RECENT']['drawdown'] = DD_sum
            stats['RECENT']['dd_start'] = DD_start
            stats['RECENT']['dd_end'] = date
  
        ldate = date
        XX_last = XX

        matchObj = re.match(r'long', f, re.I)
        if matchObj:
            print("%17s %7s %8s %7s %7s %7s %14s %7s %7s %7s %7s %7s %7s %7s %7s\n" % ("dates","long(M)","short(M)","pnl(M)","%ret","%tvr","shrp(IR)","%dd","%win","up_days","up_weeks","up_months","bpmrgn","csmrgn","fitness"))
        else:
            print("%17s %7s %8s %7s %7s %7s %14s %5s %5s %6s %6s %7s\n" % ("dates","long(M)","short(M)","pnl(M)","%ret","%tvr","shrp(IR)","%dd","%win","bpmrgn","csmrgn","fitness"))

        stats.keys().sort()
        for XX in stats.keys():
            matchObject = re.match(r'ALL', XX, re.M)
            if (matchObject):
                print("\n")

            d = stats[XX]['days']
            if(d is not None and d > 0):
                long = stats[XX]['long'] / d
                short = stats[XX]['short'] / d
                ret = stats[XX]['avg_ret'] / d * 250.0
                perwin = stats[XX]['up_days'] / d * 100.0
                turnover = stats[XX]['sh_trd'] / booksize / d if booksize > 0 else (stats[XX]['sh_trd'] / stats[XX]['sh_hld'] if stats[XX]['sh_hld'] > 0 else 0)

                drawdown = stats[XX]['drawdown'] / long * -100 if long > 0 else 0  # percent of long side

                avg = 0
                std = 0
                ir = 0

                if (d > 0):
                    avg = stats[XX]['xsy'] / d
                if (d > 2):
                    std = math.sqrt(1 / (d - 1) * (stats[XX]['xsyy'] - stats[XX]['xsy'] * stats[XX]['xsy'] / d))  

                if (std > 0):
                    ir = avg / std 

                fitness = ir / turnover if turnover > 0 else 0

                printIr = "%0.3f(%0.3f)" % (ir * math.sqrt(252), ir)

                #calc margin
                margin = const.MARGIN_MULTIPLIER * stats[XX]['pnl'] / stats[XX]['sh_trd'] if stats[XX]['sh_trd'] != 0 else "NaN"
                margin_cs = const.MARGIN_CS_MULTIPLIER * stats[XX]['pnl'] / stats[XX]['t_sh'] if stats[XX]['t_sh'] != 0 else "NaN"
                matchObj2 = re.match(r'long', f, re.I)
                if(matchObj2):
                    print("%8d-%8d %7.2f %8.2f %7.3f %7.2f %7.2f %14s %7.2f %7.2f %7d %7.2f %7.3f %7.3f\n" % (stats[XX]['dates'][0],stats[XX]['dates'][-1],long * 1.0 / +const.LONGSHORT_SCALE, short * 1.0 / +const.LONGSHORT_SCALE, stats[XX]['pnl'] * 1.0 / const.PNL_SCALE,float(ret) * 100,turnover * 100,printIr, drawdown, perwin, stats[XX]['up_days'],stats[XX]['up_weeks'],stats[XX]['up_months'],margin,margin_cs,ir * math.sqrt(252) * math.sqrt(abs(float(ret)) / turnover)))
                else:
                    print("%8d-%8d %7.2f %8.2f %7.3f %7.2f %7.2f %14s %5.2f %5.2f %6.2f %6.3f %7.3f\n" % (stats[XX]['dates'][0],stats[XX]['dates'][-1],long * 1.0 / +const.LONGSHORT_SCALE, short * 1.0 / +const.LONGSHORT_SCALE, stats[XX]['pnl'] * 1.0 / const.PNL_SCALE, float(ret) * 100,turnover * 100,printIr, drawdown, perwin, margin,margin_cs,ir * math.sqrt(252) * math.sqrt(abs(float(ret)) / turnover)))
